/*

PHYML :  a program that  computes maximum likelihood  phylogenies from
DNA or AA homologous sequences

Copyright (C) Stephane Guindon. Oct 2003 onward

All parts of  the source except where indicated  are distributed under
the GNU public licence.  See http://www.opensource.org for details.

*/

#ifndef OPTIMIZ_H
#define OPTIMIZ_H

void      Optimiz_Ext_Br(arbre *tree);
void      Optimize_Alpha(arbre *tree);
void      Optimize_Kappa(arbre *tree);
void      Optimize_Lambda(arbre *tree);
void      Optimize_Param_Parall(arbre *tree);
double    Optimize_Branch_Quad(arbre *tree, allseq *alldata, edge *b_fcus);
void      Optimize_After_Hide(arbre *tree, allseq *alldata, node *h);
void      Round_Optimize(arbre *tree, allseq *data, int n_round_max);
int       Dist_Seq_Brak(double *ax, double *bx, double *cx,
			double *fa, double *fb, double *fc,
			allseq *data, int num1, int num2, model *mod);
double    Dist_Seq_Brent(double ax, double bx, double cx, double tol,
			 double *xmin, allseq *data,
			 int num1, int num2, model *mod);
double    Kappa_Golden(double ax, double bx, double cx, double tol,
		       double *xmin, arbre *tree, allseq *alldata);
double    Lambda_Golden(double ax, double bx, double cx, double tol,
			double *xmin, arbre *tree, allseq *alldata);
double    Alpha_Golden_Br_Opt(double ax, double bx, double cx, double tol,
			      double *xmin, arbre *tree, allseq *alldata,
			      int n_opt, double *init_l);
double    Alpha_Golden(double ax, double bx, double cx, double tol,double *xmin,
		       arbre *tree, allseq *alldata);
double    Br_Len_Golden(double ax, double bx, double cx, double tol,
			double *xmin, edge *b_fcus, arbre *tree);
double    Br_Len_Brent(double *ax, double *bx, double *cx, double tol,
		       edge *b_fcus, arbre *tree, int n_iter_max, int quickdirty);
int       Br_Len_Brak(double *ax, double *bx, double *cx,
		      double *fa, double *fb, double *fc,
		      edge *b_fcus, arbre *tree);
double    Optimize_Path_Length(model *mod, allseq *alldata, edge *a,
			       int lra, edge *b, int lrb, double i_len);
void      Optimize_Param_Serie(node *a, node *d, edge *b_fcus, arbre *tree,
			       allseq *alldata, int n_passes);
double    Optimize_Dist(model *mod, double init, allseq *twoseqs);
double    Pinvar_Golden(double ax, double bx, double cx, double tol,
			double *xmin, arbre *tree, allseq *alldata, int n_iter_max);
void      Optimize_Pinvar(arbre *tree);
int       Lambda_Brak(double *ax, double *bx, double *cx,
		      double *fa, double *fb, double *fc,
		      arbre *tree);
int       Kappa_Brak(double *ax, double *bx, double *cx,
		      double *fa, double *fb, double *fc,
		      arbre *tree);
int       Alpha_Brak(double *ax, double *bx, double *cx,
		      double *fa, double *fb, double *fc,
		      arbre *tree);
int       Pinvar_Brak(double *ax, double *bx, double *cx,
		      double *fa, double *fb, double *fc,
		      arbre *tree);
void Optimiz_All_Free_Param(arbre *tree, int verbose);
void      Optimiz_RRparam_GTR(arbre *tree, int num_param);
double    RRparam_GTR_Golden(double ax, double bx, double cx, double tol,
		   	     double *xmin, arbre *tree, allseq *alldata, double *param, int n_iter_max);

int Powell_GTR_Param(arbre *tree, double *p, int n, double ftol);
double Linmin_GTR_Param(arbre *tree,double *p, double *xi, int n);
double F1dim(arbre *tree, double x, double *p, double *xi, double n);
int Mnbrak_1dim(double *ax, double *bx, double *cx,
		double *fa, double *fb, double *fc,
		arbre *tree,
		double *p,  double *xi, double n);
double Brent_1dim(double ax, double bx, double cx,
		  double tol, double *xmin,
		  arbre *tree,
		  double *p, double *xi, double n);

int Min_With_Derivatives(arbre *tree, double *p, int n, double ftol, double step_size,
			 double (*func) (), void (*dfunc)(), double (*linmin)());

#ifdef USE_LBFGS
// L-BFGS methods:
void LBFGS(arbre *tree);
static int progress(
    void *instance,
    const lbfgsfloatval_t *x,
    const lbfgsfloatval_t *g,
    const lbfgsfloatval_t fx,
    const lbfgsfloatval_t xnorm,
    const lbfgsfloatval_t gnorm,
    const lbfgsfloatval_t step,
    int n,
    int k,
    int ls
    );
static lbfgsfloatval_t evaluate(
    void *instance,
    const lbfgsfloatval_t *x,
    lbfgsfloatval_t *g,
    const int n,
    const lbfgsfloatval_t step
    );
#endif

void BFGS(arbre *tree, double *p, int n, double gtol, double step_size, double (*func)(), void (*dfunc)(), void (*lnsrch)(),int *failed);
void Brlen_BFGS(arbre *tree, double gtol, double step_size,double(*func)(), void (*dfunc)(), void (*lnsrch)(),int *failed);
void Lnsrch_RR_Param(arbre *tree, int n, double *xold, double fold, double *g, double *p, double *x,
		     double *f, double stpmax, int *check);
void Lnsrch_BLP_Param(arbre *tree, int n, double *xold, double fold,
		double *g, double *p, double *x,
		double *f, double stpmax, int *check);
void Lnsrch_Nucleotide_Frequencies(arbre *tree, int n, double *xold,
				   double fold, double *g, double *p, double *x,
				   double *f, double stpmax, int *check);
void Lnsrch_BLMixture_Param(arbre *tree, int n, double *xold, double fold, double *g, double *p, double *x,
		double *f, double stpmax, int *check);
void Lnsrch_BL_Param(arbre *tree, double fold, double *g, double *p, double *x,
		double *f, double stpmax, int *check);

void Optimize_Single_Param_Generic(arbre *tree, double *param, double lim_inf, double lim_sup, double tol, int n_max_iter, int quickdirty);
void Optimize_Single_Blprop_Generic(arbre *tree, double *param, double lim_inf, double lim_sup, double tol, int n_max_iter, int quickdirty);
int Generic_Brak(double *param,
		 double *ax, double *bx, double *cx,
		 double *fa, double *fb, double *fc,
		 double lim_inf, double lim_sup,
		 arbre *tree);
double Generic_Brent(double ax, double bx, double cx, double tol,
		     double *xmin, arbre *tree, int n_iter_max,int quickdirty);
double Blprop_Brent(double ax, double bx, double cx, double tol,
		     double *xmin, arbre *tree, int n_iter_max,int quickdirty);
void Optimize_Br_Len_BFGS(arbre *tree, int *failed);
void Optimize_Br_Len_Serie(node *a, node *d, edge *b_fcus, arbre *tree,allseq *alldata);


void Optimize_Global_Rate(arbre *tree);
double Br_Len_Brent_Default(edge *b_fcus, arbre *tree);
double Br_Len_Brent_Iter(double ax, double bx, double cx, double tol,
		    edge *b_fcus, arbre *tree, int n_iter_max, int quickdirty, int lnum);

void EM_Dist(model *mod, allseq *data);
double Dist_F_Brent(double *ax, double *bx, double *cx, double tol, int n_iter_max,
		    double *param, double *F, model *mod, arbre *tree);
double Dist_F_Brent_No_Bl(double ax, double bx, double cx, double tol, int n_iter_max,
		    double *param, double *F, model *mod);
int Dist_F_Brak(double *ax, double *bx, double *cx, double *F, double *param, model *mod);
void Opt_Dist_F(double *dist, double *F, model *mod);
//void Opt_Dist_F_No_Bl(double *dist, double *F, model *mod);
double Missing_Dist_Brent(double ax, double bx, double cx, double tol, int n_iter_max,
			  int x, int y, matrix *mat);
int Missing_Dist_Brak(double *ax, double *bx, double *cx, int x, int y, matrix *mat);
void Opt_Missing_Dist(int x, int y, matrix *mat);
int Optimiz_Alpha_And_Pinv(arbre *tree);
void Lnsrch_RR_Cov_Param(arbre *tree, int n, double *xold, double fold,
			 double *g, double *p, double *x,
			 double *f, double stpmax, int *check);
double Node_Time_Brent(double ax, double bx, double cx, double tol,
		       node *anc, node *des, arbre *tree, int n_iter_max);
double Time_Stamps_Mult_Brent(double ax, double bx, double cx, double tol,
			      arbre *tree, int n_iter_max);
double Branch_Rate_Shape_Brent(double ax, double bx, double cx, double tol,
			       double *xmin, arbre *tree, int n_iter_max);
double Node_Time_Brent_Fixed_Br_Len(double ax, double bx, double cx, double tol,
				    node *n, arbre *tree, int n_iter_max);

double Rates_Generic_Brent(double ax, double bx, double cx, double tol, double *param, arbre *tree, int n_iter_max);

#endif

